package com.zxhysy.log.annotation.advisor;

import com.zxhysy.log.annotation.LogStaticFunc;
import com.zxhysy.log.annotation.context.LogEvaluationContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.*;

/**
 * 自定义静态函数简化调度和bean方法调度
 * @author zhangxinhong
 * @since 2022/2/7 10:22
 */
@Slf4j
public class LogFuncRegister implements ApplicationContextAware, BeanFactoryAware {

    private static final Map<String, Method> FUNCTIONS = new HashMap<>();

    /**
     * bean工厂解析器
     */
    private BeanFactoryResolver beanFactoryResolver = null;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactoryResolver = new BeanFactoryResolver(beanFactory);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        // 静态方法注入前的准备
        Map<String, Object> beanWithAnnotation = applicationContext.getBeansWithAnnotation(LogStaticFunc.class);
        beanWithAnnotation.values()
                .forEach(
                        component -> {
                            Method[] methods = component.getClass().getMethods();
                            Arrays.stream(methods)
                                    .filter(method -> method.isAnnotationPresent(LogStaticFunc.class))
                                    .forEach(m -> {
                                        LogStaticFunc annotation = m.getAnnotation(LogStaticFunc.class);
                                        if (annotation != null && StringUtils.hasText(annotation.name())) {
                                            FUNCTIONS.put(annotation.name(), m);
                                        }
                                        FUNCTIONS.put(m.getName(), m);
                                        log.info("LogRecord register custom function [{}]", m);
                                    });
                        }
                );
    }

    /**
     * 注册方法
     * @param context 上下文
     */
    public void registerFunction(LogEvaluationContext context) {
        // bean 方法调用 @bean.method
        context.setBeanResolver(beanFactoryResolver);
        // 静态方法
        FUNCTIONS.forEach(context::registerFunction);
    }
}
